#pragma once
#include "trianglesurface.h"
#include "../math/primitives.h"
#include "../engine/dynamicarray.h"
#include "../engine/essential.h"
#include "../transformation/camera.h"

// ================================================================================================
// Class that holds mesh objects
// ================================================================================================
class MeshObject {

    private:

        DynamicArray<TriangleSurface> mesh;
        DynamicArray<TriangleAcc> meshacc;
        DynamicArray<TriangleAccDP> meshaccdp;
        uint faces;

        void CreateTriangle(uint current);
        void CreateTriangleSquare(uint current);

    public:

        // -- default constructor
        MeshObject();
        ~MeshObject();

        // -- overloaded operators
        TriangleSurface& operator[](const uint i);
        const TriangleSurface& operator[](const uint i) const;

        // -- accessor methods
        uint& GetNumFaces();
        const uint& GetNumFaces() const;
        DynamicArray<TriangleAccDP> GetTriAccelsDP();
        DynamicArray<TriangleAcc> GetTriAccels();

        // -- mutator methods
        void AppendFace(const TriangleSurface& trianglesurface);

        // -- public methods
        void CreateMesh();
        void OptimizeMesh();
        MeshObject TransformToCamSpace(Camera& cam);
};

// ================================================================================================
// Default constructor
// ================================================================================================
inline MeshObject::MeshObject() : mesh(), faces(0) {
}

inline MeshObject::~MeshObject() {

}

// ================================================================================================
// Overloaded operators
// ================================================================================================
inline TriangleSurface& MeshObject::operator[](const uint i) {
    return mesh[i];
}

inline const TriangleSurface& MeshObject::operator[](const uint i) const {
    return mesh[i];
}

// ================================================================================================
// Accessor methods
// ================================================================================================
inline uint& MeshObject::GetNumFaces() {
    return faces;
}

inline const uint& MeshObject::GetNumFaces() const {
    return faces;
}

inline DynamicArray<TriangleAccDP> MeshObject::GetTriAccelsDP() {
    return meshaccdp;
}

inline DynamicArray<TriangleAcc> MeshObject::GetTriAccels() {
    return meshacc;
}

// ================================================================================================
// Mutator methods
// ================================================================================================
inline void MeshObject::AppendFace(const TriangleSurface& trisurface) {
    mesh.Append(trisurface);
}

// ================================================================================================
// Optimize the mesh
// ================================================================================================
inline void MeshObject::OptimizeMesh() {
    for(uint i = 0; i < faces; ++i) {
        meshaccdp.Append(mesh[i].CalcOptimized4x4());
    }
}

// ================================================================================================
// Transform mesh points to camera space
// ================================================================================================
inline MeshObject MeshObject::TransformToCamSpace(Camera& cam) {
    Matrix4x4 viewtrans = cam.GetCamTransform();
    MeshObject toview = *this;

    for(uint i = 0; i < GetNumFaces(); ++i) {
        toview[i].Transform(viewtrans);
    }

    return toview;
}